package deprecated;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.swing.event.ListSelectionEvent;


import measures.DistanceSet;
//TODO Ausgabeanfang anpassen, sodass alle Ausgaben ohne Leerzeichen beginnen, wenn möglich. 

/**
 * The methods of the class CreateXML compute a xml for given input.
 * Words that can be translated stand in xml tags e.g. <xml translation = "translated_words"> x <\xml>.
 * Words that the fuzzy match doesn´t contain are written as single words without xml-tags.
 * @author thomas
 *
 */
public class CreateXMLalt {

	private String xmlstring;
	private String sentTest;
	private String sentTrain_de;
	private String sentTrain_en;
	private String alignmentTrain;
	
	private ArrayList<String> matchPath;
	private ArrayList<String> sourceList;
	private ArrayList<String> tmsourceList;
	private ArrayList<String> tmtargetList;

	
	private LinkedHashMap<Integer, List<Integer>> alignmentMap;
	
	private SortedSet<Integer> sortedAlignments;
	
	private DistanceSet distanceSet;
 
	
	
	/**
	 * Constructor for CreateXML Objects with values for test sentence, trainings sentences in German 
	 * and English as well as alignments between this trainings sentences.
	 * Creates a matchPath via distanceSet (levenshtein distance between sentTest (=source) and 
	 * sentTrain_de (=tmsource). 
	 */
	public CreateXMLalt(String str){
		
		String [] input = str.split("\t");
		this.sentTest = input[0].split("\\|\\|\\|")[1];
		this.sentTrain_de = input[1].split("\\|\\|\\|")[1];
		this.sentTrain_en = input[2].split("\\|\\|\\|")[1];
		this.alignmentTrain = input[3].split("\\|\\|\\|")[1];
		
		this.distanceSet = new measures.DistanceSet(this.sentTest, this.sentTrain_de);
		
		this.matchPath = this.distanceSet.getBacktrace();
		
		mapAlignment();
		readSentsIntoList();
	}
	
	/**
	 * This method just prints out: the source, tmsource, tmtarget and alignment.
	 */
	public void printsentLists(){
		
		//System.out.println(this.sentTest.length());
		//System.out.println(this.sentTrain_de.length());
		//System.out.println(this.sentTrain_en.length());
		
		//System.out.println(this.matchPath.toString() + " " + this.matchPath.size());
		
		System.out.println(this.sourceList.toString());
		System.out.println(this.tmsourceList.toString());
		System.out.println(this.tmtargetList.toString());
		
		System.out.println(this.alignmentMap.toString());

	}
	
	/**
	 * A function call to provide the translation.
	 * @return Returns the translatedXML as String.
	 */
	public String getTranslation(){
		return this.getXML();
	}
	
	/**
	 * Creates the alignment as HashMap.
	 * If the map already contains the given key, the current key will be appended.
	 * Else: a new key-value pair is inserted in the HashMap
	 */
	private void mapAlignment(){
		
		this.alignmentMap = new LinkedHashMap<Integer, List<Integer>>();
		
		String[] splitAlign = alignmentTrain.split(" ");
		
		for(String s: splitAlign){
			
			String[] splitSoTa = s.split("-");
			if(this.alignmentMap.containsKey(Integer.parseInt(splitSoTa[1]))){
				this.alignmentMap.get(Integer.parseInt(splitSoTa[1])).add(Integer.parseInt(splitSoTa[0]));
			}else{
				this.alignmentMap.put(Integer.parseInt(splitSoTa[1]), new ArrayList<Integer>(Arrays.asList(Integer.parseInt(splitSoTa[0]))));
			}
						
		}
		
		this.sortedAlignments = new TreeSet<Integer>(this.alignmentMap.keySet());
	}
	
	/**
	 * Creates finally two lists: sourceList and tmsourceList.
	 * Therefore it will be differentiate about following cases:
	 * Matching: sourceList as well as tmsourceList get the correspondent value.
	 * Insertion: sourceList gets a null-value, tmsourceList the correspondent value from tmsource.
	 * Deletion: sourceList gets the correspondant value from source, tmsource a null-value.
	 */
	private void readSentsIntoList(){
		
		sourceList = new ArrayList<String>();
		tmsourceList = new ArrayList<String>();
		tmtargetList = new ArrayList<String>();
		
		
		ArrayList<String> sSplit = new ArrayList<String>(Arrays.asList(this.sentTest.split(" ")));
		ArrayList<String> tmsSplit = new ArrayList<String>(Arrays.asList(this.sentTrain_de.split(" ")));
		ArrayList<String> tmtSplit = new ArrayList<String>(Arrays.asList(this.sentTrain_en.split(" ")));
		
		this.tmtargetList = tmtSplit;
		
		for(int i = 0; i < this.matchPath.size(); i++){
			
			if(this.matchPath.get(i).equals(" Match ") || this.matchPath.get(i).equals(" Replacement ")){
				
				this.sourceList.add(sSplit.get(i));
				this.tmsourceList.add(tmsSplit.get(i));
					
			}
			if(this.matchPath.get(i).equals(" Insertion ")){	
			
				//TODO wieder andersrum gedacht? liefert trotzdem richtiges Ergebnis - warum? :D
				this.sourceList.add(null);
				sSplit.add(i, null);
				
				this.tmsourceList.add(tmsSplit.get(i));
				
			}
			if(this.matchPath.get(i).equals(" Deletion ")){	
				
				this.sourceList.add(sSplit.get(i));
				
				this.tmsourceList.add(null);
				tmsSplit.add(i, null);				
			}	
		}
		
	}
	//TODO Die musst du erklären - was tut mapOffSet? wie bist du drauf gekommen es wo wann zu erhören?
	//TODO Wozu dienen die formatting hacks? ^^
	/**
	 * Constructs the translation in a xml-frame.
	 * 
	 * @return Returns the translated XML as String.
	 */
	private String translateXML(){
		
		xmlstring = new String();
		
		
		int i = 0;
		Boolean done = false;
		int mapOffset = 0;
		
		ArrayList<ArrayList<String>> outputlist = new ArrayList<ArrayList<String>>();
		ArrayList<ArrayList<String>> outputlistMis = new ArrayList<ArrayList<String>>();

		
		for (int j = 0; j < this.matchPath.size()*2; j++) {
			  outputlist.add(null);
		}
		
		while(!done){
			
			if(i>this.matchPath.size()-1){
				done = true;
			}
			
			if(!done && this.matchPath.get(i).equals(" Match ")){
						
					while(i<this.matchPath.size() && this.matchPath.get(i).equals(" Match ")){
						
						if(this.alignmentMap.containsKey(i-mapOffset)){
							for(int value: this.alignmentMap.get(i-mapOffset)){	
								
								if(!this.tmtargetList.get(value).equals("<s>") && !this.tmtargetList.get(value).equals("</s>") && !this.tmtargetList.get(value).equals("")){
									
									
									if(outputlist.get(value)== null){
										ArrayList<String> tmplist = new ArrayList<String>();
										
										
										tmplist.add(this.tmtargetList.get(value));
										outputlist.set(value, tmplist);
									}else{
										
										outputlist.get(value).add(this.tmtargetList.get(value));
									}
									//removing already written entries to prevent multiple instances of the tmtarget-token in case of multiple alignment assignments
									this.tmtargetList.set(value, "");
									
								}
							}
						}
						i++;
					}
					
				}else{
				
					ArrayList<String> block = new ArrayList<String>();
					
					
					while(i<this.matchPath.size() && !this.matchPath.get(i).equals(" Match ")){
						
						if(this.matchPath.get(i).equals(" Replacement ")){
							if(this.alignmentMap.containsKey(i-mapOffset)){
								for(int value: this.alignmentMap.get(i-mapOffset)){	
										
										
										if(outputlist.get(value)== null){
											ArrayList<String> tmplist = new ArrayList<String>();
											
											tmplist.add("REP");
											
											outputlist.set(value, tmplist);
										}else{
											outputlist.get(value).add("REP");
											if(!block.isEmpty()){
												outputlistMis.add(block);
												
											}
											block = new ArrayList<String>();
										}
								}
							}
							block.add(this.sourceList.get(i) + " REP");		
							i++;
						
						}else{
							if(this.matchPath.get(i).equals(" Deletion ")){
								
								mapOffset ++;
								
								block.add(this.sourceList.get(i) + " DEL");
								i++;
							
							}else{
								if(this.matchPath.get(i).equals(" Insertion ")){
									
									
									
									if(this.alignmentMap.containsKey(i-mapOffset)){
										for(int value: this.alignmentMap.get(i-mapOffset)){	
												
												
												if(outputlist.get(value)== null){
													ArrayList<String> tmplist = new ArrayList<String>();
													
													tmplist.add("INS");
													
													outputlist.set(value, tmplist);
												}else{
													outputlist.get(value).add("INS");
												}
										}
									}
									
									i++;
							}
						}
							
						}
					}
					if(!block.isEmpty()){
						outputlistMis.add(block);
						
					}
			
			}
		}	
		
		
		
		//handling spaces
		this.xmlstring = xmlstring.replace("translation=\" ", "translation=\"");
		
		//handling single deletion case
		this.xmlstring = xmlstring.replace("\"> x </xml> <xml translation=\"", " ");
		
		//handling spaces
		this.xmlstring = xmlstring.replace("<xml translation=\"\"> x </xml>\"", "");
			
		this.xmlstring = xmlstring.replace("<xml translation=\"\"> x </xml>", "");
		
		this.xmlstring = xmlstring.replace("  " , " ");
		
		//return this.xmlstring;
		//outputlist.removeAll(Collections.singleton(null));
		//testcase
		
		//cleaning up outputlist
		ArrayList<String> outputlistMatch = new ArrayList<String>();
		
		for(ArrayList<String> arr: outputlist){
			if(arr != null){
				for(String str: arr){
					outputlistMatch.add(str);
				}
			}
		}
		
		
		
		
		outputlistMatch.removeAll(Collections.singleton(null));
		outputlistMatch.removeAll(Collections.singleton("INS"));
		
		for(int j=0;j<outputlistMatch.size()-1;j++){
			
			if(outputlistMatch.get(j) == null && outputlistMatch.get(j+1) == null){
				outputlistMatch.remove(j);
					j=0;
			}
			if(outputlistMatch.get(j) == "REP" && outputlistMatch.get(j+1) == "REP"){
				outputlistMatch.remove(j);
					j=0;
			}
		}
		
		int c = 0;
		for(int j=0;j<outputlistMatch.size();j++){
			
			if(outputlistMatch.get(j) == "REP" ){
				c++;
			}
		}
		
		return outputlistMatch.toString() + " " + c + " "  + outputlistMis.size() + " " + outputlistMis.toString();
	}
	
	
	private String getXML(){
		
		//TODO: keys have to be sorted!
		
		ArrayList<HashMap<String, String>> outlist = new ArrayList<HashMap<String, String>>(this.alignmentMap.size());
		int mapOffset = 0;
		
		for(int currkey: this.sortedAlignments){
			
			LinkedHashMap<String, String> tempmap = new LinkedHashMap<String, String>();
			
			for(int i:this.alignmentMap.get(currkey)){
				
				if(this.matchPath.get(i).equals(" Match ") && !this.tmtargetList.get(currkey).equals("")){
					
					tempmap.put(this.tmtargetList.get(currkey), "MATCH");
					this.tmtargetList.set(currkey, "");
					this.sourceList.set(i, "");
					outlist.add(tempmap);
				}
				
				if(this.matchPath.get(i).equals(" Replacement ") && this.sourceList.get(i) != ""){
					
					tempmap.put(this.sourceList.get(i), "REPL");
					this.sourceList.set(i, "");
					this.tmtargetList.set(currkey, "");
					outlist.add(tempmap);
				}
				
				if(this.matchPath.get(i).equals(" Deletion ") && this.sourceList.get(i) != ""){
					
					mapOffset ++;
					tempmap.put(this.sourceList.get(i), "DEL");
					this.sourceList.set(i, "");
					outlist.add(tempmap);
				}
			}	
			
			
			
			
			
			
		}
		
		
		
		return outlist.toString();
	}
	
	
}
